part of common_lib_plugin;

extension StringCheckExtension on String? {
  bool get isNum {
    if (isNull) {
      return false;
    }
    return num.tryParse(this ?? '') is num;
  }

  bool get isNotNull {
    return this != null && this!.isNotEmpty;
  }

  bool get isNull {
    return this == null || this!.isEmpty;
  }

  ///检查密码, 最少一个大写, 一个小写字母, 一个数字 且长度最少8位
  bool checkPassword() => _hasMatch(this, r"^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$");

  ///检查密码, 最少一个字母, 一个数字 且长度最少8位
  bool checkPasswordSimple() => _hasMatch(this, r"^(?=.*[A-Za-z])(?=.*\d).{8,}$");

  ///检查11位手机号
  bool kIsPhone() => _hasMatch(this, r'^1\d{10}$');

  bool kIsURL() => _hasMatch(this, r"(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");

  bool kIsWalletAddress() => _hasMatch(this, r"^0x[a-fA-F0-9]{40}");

  ///是否匹配
  static bool _hasMatch(String? value, String pattern) {
    return (value == null) ? false : RegExp(pattern).hasMatch(value);
  }
}

extension StringExtension on String {
  String toPinyin({PinyinFormat format = PinyinFormat.WITHOUT_TONE, String separator = ' '}) {
    return PinyinHelper.getPinyinE(this, format: format, separator: separator);
  }

  String toHtmlUnescape() {
    return HtmlUnescape().convert(this);
  }

  String getLastName({int lengthLimit = 2}) {
    if (length <= lengthLimit) return this;
    var content = this;
    if (contains('•')) {
      content = substring(0, indexOf('•'));
    } else if (contains('・')) {
      content = substring(0, indexOf('・'));
    } else if (contains('·')) {
      content = substring(0, indexOf('·'));
    }
    if (content.length <= lengthLimit) return content;
    return content.substring(content.length - lengthLimit);
  }

  String fileNameAddTimeStamp() {
    if (!contains('.')) return this;
    var list = split('.');
    if (list.length < 2) return this;
    return '${list[0]}${DateTime.now().millisecondsSinceEpoch}.${list[1]}';
  }

  String md5Str() {
    Uint8List content = const Utf8Encoder().convert(this);
    Digest digest = md5.convert(content);
    return digest.toString();
  }

  String subStringPrefix(int lengthValue) {
    if (length <= lengthValue) {
      return this;
    } else {
      return substring(0, lengthValue);
    }
  }

  String subStringSuffix(int lengthValue) {
    if (length <= lengthValue) {
      return this;
    } else {
      return substring(length - lengthValue);
    }
  }

  String fillingPrefixZero(int minLength) {
    if (length >= minLength) {
      return this;
    } else {
      String prefix = '';
      for (var i = 0; i < minLength - length; i++) {
        prefix += '0';
      }
      return '$prefix$this';
    }
  }

  String fillingSuffixZero(int minLength, {bool formatInteger = false, bool isNum = true}) {
    if (!replaceAll(',', '').isNum) {
      if (isNum) {
        return this;
      } else {
        var len = minLength - length > 0 ? minLength - length : 0;
        return '$this${'0' * len}';
      }
    }
    if (!contains('.')) {
      if (formatInteger) {
        return '$this.${'0' * minLength}';
      }
      return this;
    }
    String int = substring(0, indexOf('.'));
    String decimal = replaceFirst(int, '');
    if (decimal.isEmpty) decimal = '.';
    while (decimal.length - 1 < minLength) {
      decimal += '0';
    }
    if (decimal == '.') {
      decimal = '';
    }
    return int + decimal;
  }

  String trimPrefixZero() {
    if (!replaceAll(',', '').isNum) return this;
    String decimal = this;

    while (decimal.isNotEmpty && decimal.startsWith('0')) {
      decimal = decimal.substring(1);
    }
    return decimal;
  }

  String trimLastZero() {
    if (!replaceAll(',', '').isNum) return this;
    if (!contains('.')) return this;
    String int = substring(0, indexOf('.'));
    String decimal = replaceFirst(int, '');
    while (decimal.isNotEmpty && decimal.endsWith('0')) {
      decimal = decimal.substring(0, decimal.length - 1);
    }
    if (decimal == '.') {
      decimal = '';
    }
    return int + decimal;
  }

  int textLines({required TextStyle textStyle, required double width}) {
    TextSpan textSpan = TextSpan(text: this, style: textStyle);
    TextPainter textPainter = TextPainter(text: textSpan, textDirection: TextDirection.ltr);
    textPainter.layout(maxWidth: width.floorToDouble());

    // logV('${textPainter.height},${textPainter.preferredLineHeight}， ${(textPainter.height / textPainter.preferredLineHeight)}');
    return textPainter.height ~/ textPainter.preferredLineHeight;
  }

  String splitStringContent() {
    return split('').join("\u{200B}").fixEmojiError();
  }

  String fixEmojiError() {
    return replaceAll('\ufe0f\u20e3', '\u20e3\ufe0f');
  }

  ///按位数进行缩略
  String overflow(int size) {
    var result = '';
    if (length > size) {
      result = '${substring(0, size - 1)}...';
    } else {
      result = this;
    }
    return result;
  }

  int utf8Length() {
    return const Utf8Encoder().convert(this).length;
  }

  int commonCharLength() {
    var byteSize = 0;
    for (var i = 0; i < length; i++) {
      var charCode = codeUnits[i];
      if (0 <= charCode && charCode <= 0x7ff) {
        byteSize += 1;
      } else if (2048 <= charCode && charCode <= 0x7FFFFFFF) {
        byteSize += 2;
      }
    }
    return byteSize;
  }

  String? handleBrTag() {
    return replaceAll('<br>', '\n');
  }

  ///隐藏邮箱中间部分
  String? hideEmail() {
    String perfixEmail = '';
    String suffixEmail = '';

    final list = split('@');
    if (list.length == 2) {
      perfixEmail = list.first.replaceRange(2, null, '****');
      String firstSuffix = '';
      final suffixList = list.last.split('.');
      if (suffixList.length == 2) {
        firstSuffix = suffixList.first.replaceRange(2, null, '****');
        suffixEmail = '$firstSuffix.${suffixList.last}';
      }
    }

    return '$perfixEmail@$suffixEmail';
  }

  ///隐藏邮箱中间部分
  String? hidePhone() {
    if (length > 7) {
      return replaceRange(3, 7, '****');
    }

    return this;
  }

  ///获取文本的Size, value: 文本内容；maxWidth：文本框的最大宽度；maxLines：文本支持最大多少行
  Size calculateTextSize({
    required TextStyle style,
    required double maxWidth,
    required int maxLines,
    required BuildContext context,
  }) {
    String value = filterText(this);
    TextPainter painter = TextPainter(

        ///AUTO：华为手机如果不指定locale的时候，该方法算出来的文字高度是比系统计算偏小的。
        locale: Localizations.localeOf(context),
        maxLines: maxLines,
        textDirection: TextDirection.ltr,
        text: TextSpan(text: value, style: style));
    painter.layout(maxWidth: maxWidth);

    ///文字的宽度:painter.width
    return painter.size;
  }

  static String filterText(String text) {
    String tag = '<br>';
    while (text.contains('<br>')) {
// flutter 算高度,单个\n算不准,必须加两个
      text = text.replaceAll(tag, '\n\n');
    }
    return text;
  }

  String breakWord() {
    if (isEmpty) {
      return this;
    }
    String breakWord = '';
    for (var element in runes) {
      breakWord += String.fromCharCode(element);
      breakWord += '\u200B';
    }
    return breakWord;
  }

  static double toDoubleSafety(String? value, {double defaultValue = 0}) {
    if (value != null) {
      try {
        return double.parse(value);
      } catch (err) {
        logW('CountDownController _parseDouble() occur exception : ${err.toString()}');
      }
    }
    return defaultValue;
  }

  ///计算文本Size
  static Size kCalculateTextSize({required String text, required TextStyle style}) {
    final textSpan = TextSpan(
      text: text,
      style: style,
    );
    final tp = TextPainter(text: textSpan, textDirection: TextDirection.ltr);
    tp.layout();
    return tp.size;
  }

  bool isToday({String format = 'YYYY-MM-dd'}) {
    var selectedDate = DateTime.tryParse(this);
    if (selectedDate == null) return false;
    var selectedDateStr = selectedDate.millisecondsSinceEpoch.formatTime(format);
    var currentDateStr = DateTime.now().millisecondsSinceEpoch.formatTime(format);
    return selectedDateStr == currentDateStr;
  }

  /// def duration 24h
  bool isValidDate({Duration? durationOffset, String format = 'YYYY-MM-dd HH:mm'}) {
    var offset = durationOffset ?? const Duration(days: 1);
    var selectedDate = DateTime.tryParse(this);
    if (selectedDate == null) return false;
    var validDate = selectedDate.add(offset);
    return validDate.isAfter(DateTime.now());
  }
}
